

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;

public class Ant implements defAnt {

	//Fields
    
	private static final int NOFOOD = 20;
	private static final int GOTFOOD = 40;

	public static enum DIRECTION { leftBottomLeft, left, rightTopRight, right, leftTopTop, top, rightBottomBottom, bottom, leftTopLeft, leftTop, leftBottomBottom,
		leftBottom, rightTopTop, rightTop, rightBottomRight, rightBottom };//Reihenfolge wichtig!!!!
	public static final DIRECTION [] defaultPrefDir = { DIRECTION.leftBottomLeft, DIRECTION.left, DIRECTION.rightTopRight, DIRECTION.right, DIRECTION.leftTopTop, DIRECTION.top, DIRECTION.rightBottomBottom, DIRECTION.bottom, DIRECTION.leftTopLeft, DIRECTION.leftTop, DIRECTION.leftBottomBottom, DIRECTION.leftBottom, DIRECTION.rightTopTop, DIRECTION.rightTop, DIRECTION.rightBottomRight, DIRECTION.rightBottom };
	private static final int [] dirActions = { 13, 12, 31, 32, 11, 21, 33, 23, 12, 11, 23, 13, 21, 31, 32, 33 };
	// 1.Stelle: x-Coordinate, 1->-1, 2->0, 3->1;
	// 2.Stelle: y-Coordinate, 1->-1, 2->0, 3->1.
		
	private static Random rand = new Random();
	
	//Attributes
	public int mark=0;
	private Point position;
	private PTrail pTrail;
	public int food = NOFOOD;
	private DIRECTION [] prefDir;
	private boolean secondDirectionChosen = false;
	private boolean waytoHomeDenied=false;
	private boolean needtoEvade=false;
	private int counter;
	private boolean solidborder;
	private DIRECTION beforeLastDir;
	
	private BackTrack btrack=new BackTrack(250);
	
	private AntSimulation antSim;
	
	//Constructor
	public Ant( Point p ,AntSimulation as){
		antSim=as;
		
		position = new Point( p );
		prefDir = defaultPrefDir.clone();
		antSim.getForestground()[p.x][p.y] *= -1;
	}
	
	
	public Ant( Point p, DIRECTION dir ,AntSimulation as){
		antSim=as;
		
		position = new Point( p );
		prefDir = defaultPrefDir.clone();
		for(int i=0; i<16; i++){
			changeOrder(defaultPrefDir[rand.nextInt(defaultPrefDir.length)]);
		}
		changeOrder( dir );
		antSim.getForestground()[p.x][p.y] *= -1;
		pTrail = new PheromoneTrail(antSim);
		beforeLastDir = prefDir[15];
	}
	
	
	/*
	Methods
	*/
	
	//getter - Methods
	
	public int getMark(){
		return this.mark;
	}
	public void setMark(int zahl){
		this.mark=zahl;
	}
	public int getX(){
		return this.position.x;
	}
	
	public int getY(){
		return this.position.y;
	}
	
	public int getFood(){
		return this.food;
	}
	
	public PTrail getPtrail(){
		return (PheromoneTrail) this.pTrail;
	}
	

	
	
	// other Methods

	private void changeOrder( DIRECTION dir ){
		DIRECTION saveDir = dir, tmpDir = prefDir[0];
		int i = 0;
		while( prefDir[i] != dir ){
			tmpDir = prefDir[i];
			prefDir[i] = saveDir;
			saveDir = tmpDir;
			i++;
		}
		prefDir[i] = tmpDir;
	}
	
	
	/*private void goHome(){
		
		//x>0
		if((antSim.anthill_rectangle.getMidPointX()-position.x)>0 
				&& (antSim.anthill_rectangle.getMidPointY()-position.y)>0)
				changeOrder(DIRECTION.rightBottom);
		else if(antSim.anthill_rectangle.getMidPointX()-position.x>0 
				&& antSim.anthill_rectangle.getMidPointY()-position.y<0)
				changeOrder(DIRECTION.rightTop);
		else if(antSim.anthill_rectangle.getMidPointX()-position.x>0 
				&& antSim.anthill_rectangle.getMidPointY()-position.y==0)
			changeOrder(DIRECTION.right);
		//x<0
		else if(antSim.anthill_rectangle.getMidPointX()-position.x<0 
				&& antSim.anthill_rectangle.getMidPointY()-position.y>0)
				changeOrder(DIRECTION.leftBottom);
		else if(antSim.anthill_rectangle.getMidPointX()-position.x<0 
				&& antSim.anthill_rectangle.getMidPointY()-position.y<0)
			changeOrder(DIRECTION.leftTop);
		else if(antSim.anthill_rectangle.getMidPointX()-position.x<0 
				&& antSim.anthill_rectangle.getMidPointY()-position.y==0)	
				changeOrder(DIRECTION.left);
		//x==0
		else if(antSim.anthill_rectangle.getMidPointX()-position.x==0 
				&& antSim.anthill_rectangle.getMidPointY()-position.y<0)
				changeOrder(DIRECTION.top);
		else if(antSim.anthill_rectangle.getMidPointX()-position.x==0 
				&& antSim.anthill_rectangle.getMidPointY()-position.y>0)
				changeOrder(DIRECTION.bottom);
		
		System.out.println(prefDir[0]);

	}//goHome()*/
	
	private void goHome(Point nextPoint){
		//Gitter von acht feldern um ameisenhuegel->entsprechend richtung
		
		if(nextPoint.x<antSim.anthill_rectangle.x){
			if(nextPoint.y<antSim.anthill_rectangle.y){
				changeOrder(DIRECTION.rightBottom);
			}
			else if(nextPoint.y>antSim.anthill_rectangle.y2){
				changeOrder(DIRECTION.rightTop);
			}
			else{
				changeOrder(DIRECTION.right);
			}
		}
		else if(nextPoint.x>antSim.anthill_rectangle.x2){
			if(nextPoint.y<antSim.anthill_rectangle.y){
				changeOrder(DIRECTION.leftBottom);
			}
			else if(nextPoint.y>antSim.anthill_rectangle.y2){
				changeOrder(DIRECTION.leftTop);
			}
			else{
				changeOrder(DIRECTION.left);
			}
		}
		else{
			if(nextPoint.y<antSim.anthill_rectangle.y){
				changeOrder(DIRECTION.bottom);
			}
			else if(nextPoint.y>antSim.anthill_rectangle.y2){
				changeOrder(DIRECTION.top);
			}
		}
		
		
		
	}//goHome
	
	private void evade(){   //neu  //evade if way to home is denied
		/*int change=(int) (Math.random()*2);
		if(change==0)
			change=1;
		else if(change==1)
			change=2;
		else
			change=3;
		int neu=toHome.ordinal()+change;
		
		if(neu>=defaultPrefDir.length)//avoid IndexoutodboundsException
			neu-=defaultPrefDir.length;
		
		changeOrder(defaultPrefDir[neu]);*/
		
		/*for(int j=0; j<16; j++){//damit zickzacklaufen nach ablage verhindert wird  //neu
			changeOrder(defaultPrefDir[rand.nextInt(defaultPrefDir.length)]);
		}
		*/
		
		for(int j=0; j<16; j++){//damit zickzacklaufen nach ablage verhindert wird  //neu
			changeOrder(defaultPrefDir[rand.nextInt(defaultPrefDir.length)]);
		}
		
		int back=btrack.pop();
		if(mark==1){
			System.out.println("back"+back);
		}
		for(int i=0;i<dirActions.length;i++){
			if(back==dirActions[i]){
				changeOrder(defaultPrefDir[i]);
			}
		}
		
	}
	
	private boolean stepDirection( Point nextPoint ){
		
		
		needtoEvade=false;

		if(this.food==GOTFOOD){
			
			
			goHome(nextPoint);
		
		}
		
		if(waytoHomeDenied&&counter>0&&this.food==GOTFOOD){
			needtoEvade=true;
			evade();
			counter--;
			if(counter==0)
				waytoHomeDenied=false;
		}
		
		for( int i = 0; i < prefDir.length; i++ ){
		
			
			DIRECTION secDir = prefDir[1];
			if( i > 1 )
				secondDirectionChosen = false;
			
			if(i>0&&this.food==GOTFOOD&&needtoEvade==false){//go home is denied and ant not evads in the moment  //neu
				
			
			
			
			if(solidborder){//id way to home is denied by food
				waytoHomeDenied=true;
				counter=250;
				
				break;
			}
			break;
			}
			
			
			
			
			
			DIRECTION actDir = prefDir[i];
			 int action = Ant.dirActions[ actDir.ordinal() ];
			
			if( actDir.ordinal()%2 == 0 ){
				secondDirectionChosen = true;
				secDir = Ant.defaultPrefDir[ actDir.ordinal() + 1 ];
			}
			
			int akty = nextPoint.y + action%10 - 2;//xdiff;
			int help=action/10;
			 int aktx = nextPoint.x + help - 2;//ydiff;
		
			if( i > 0 && actDir == beforeLastDir )
				continue;
			
			
			
			if( aktx >= 0 && aktx < antSim.getSimWidth() && akty >= 0 
					&& akty < antSim.getSimHeight() 
					&& antSim.getForestground()[aktx][akty] > 0 ){
				nextPoint.x = aktx;
				nextPoint.y = akty;
				
				if(!needtoEvade){
					if(mark==1)
						System.out.println("push"+action);
				btrack.push(action);
				
				}
				
				if( i > 0 )
					beforeLastDir = prefDir[0];
				changeOrder( prefDir[i] );
				if( secondDirectionChosen ){
					changeOrder( secDir );
				}
				return true;
			}
			
			
			
			if( aktx > 0 && aktx < antSim.getSimWidth() 
					& akty > 0 && akty < antSim.getSimHeight() 
					&& antSim.getForestground()[aktx][akty] < -255 && this.food == NOFOOD ){
				this.food = GOTFOOD;
				antSim.getForestground()[aktx][akty] += GOTFOOD;
				//goHome();
				if( antSim.getForestground()[aktx][akty] >= -255 )
					antSim.getForestground()[aktx][akty] = 1;
				return false;
			}
			//wenn die Ameisen am Huegel angekommen sind, geben sie das Futter ab
			
			if(aktx > 0 && aktx < antSim.getSimWidth() 
					& akty > 0 && akty < antSim.getSimHeight() &&antSim.getForestground()[aktx][akty] < -255){
				solidborder=true;
			}
			else
				solidborder=false;
			if(antSim.anthill_rectangle.isAtBorder(aktx, akty) ){
				this.food = NOFOOD;
				//prefDir = defaultPrefDir.clone();
				for(int j=0; j<16; j++){//damit zickzacklaufen nach ablage verhindert wird  //neu
					changeOrder(defaultPrefDir[rand.nextInt(defaultPrefDir.length)]);
				}
			}
		}
		return false;
	}

	
	private void validatePheromoneTrail(){
		pTrail.validate( position, this.food );
	}
	
	
	public void draw( Graphics g ){
		Color tmp;
		if( food == GOTFOOD )
			tmp = Color.red;
		else
			tmp = Color.black;
//		g.setColor(tmp);
//		g.fillRect( position.x, position.y, 1, 1);
		antSim.setUnderlayerColor(position.x, position.y, tmp.getRGB());
	}

	
	public void drawTrail( Graphics g ){
		pTrail.draw( g );
	}
	
	
	public void stepForward(){
		Point nextPoint = new Point( position );
		if( this.stepDirection( nextPoint ) ){
			antSim.getForestground()[position.x][position.y] *= -1;
			antSim.getForestground()[nextPoint.x][nextPoint.y] *= -1;
			position = nextPoint;
			validatePheromoneTrail();
		}
	}


	
	
}
